home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Mac Power 1997 December
/
MACPOWER-1997-12.ISO.7z
/
MACPOWER-1997-12.ISO
/
AMUG
/
PROGRAMMING
/
Raven 1.2.sit
/
Raven 1.2
/
Source
/
Foundation
/
Common
/
ZFixedAllocator.cpp
< prev
next >
Wrap
Text File
|
1997-07-13
|
5KB
|
208 lines
/*
* File: ZFixedAllocator.cpp
* Summary: A class that can speedily allocate fixed size blocks.
* Written by: Jesse Jones
*
* Copyright ゥ 1997 Jesse Jones.
* For conditions of distribution and use, see copyright notice in ZTypes.h
*
* Change History (most recent first):
*
* <2> 7/13/97 JDJ Inlined HasBlock.
* <1> 1/29/96 JDJ Created
*/
#include <ZFixedAllocator.h>
#include <ZDebug.h>
#include <ZExceptions.h>
#if DEBUG
#include <ZMemUtils.h>
#endif
// ===================================================================================
// struct SBlock
// This is a variable length struct. If the block is free the first four bytes
// are a pointer to the next free block. Otherwise the contents are the user data.
// ===================================================================================
struct SBlock {
SBlock* nextFree;
};
// ===================================================================================
// class TFixedAllocator
// ===================================================================================
//---------------------------------------------------------------
//
// TFixedAllocator::~TFixedAllocator
//
//---------------------------------------------------------------
TFixedAllocator::~TFixedAllocator()
{
DisposePtr((Ptr) mBlocks);
}
//---------------------------------------------------------------
//
// TFixedAllocator::TFixedAllocator
//
//---------------------------------------------------------------
TFixedAllocator::TFixedAllocator(ulong blockSize, ulong maxBlocks)
{
ASSERT(blockSize >= sizeof(SBlock));
ASSERT(maxBlocks > 0);
ASSERT(blockSize*maxBlocks < 4*1024L*1024L);
mBlockSize = blockSize;
mMaxBlocks = maxBlocks;
mBlocks = reinterpret_cast<SBlock*>(NewPtr(mBlockSize*mMaxBlocks));
ThrowIfNil(mBlocks);
mBlockCount = 0;
mMaxBlockCount = 0;
mNextFreeBlock = mBlocks;
mEndBlock = reinterpret_cast<SBlock*>((char*) mBlocks + mBlockSize*mMaxBlocks);
// Link all the blocks up.
SBlock* block = mNextFreeBlock;
while (block != nil) {
SBlock* next = this->GetNextBlock(block);
block->nextFree = next;
block = next;
}
}
//---------------------------------------------------------------
//
// TFixedAllocator::Allocate
//
//---------------------------------------------------------------
void* TFixedAllocator::Allocate()
{
ASSERT(mBlockCount <= mMaxBlockCount);
ASSERT(mBlockCount <= mMaxBlocks);
ASSERT((mNextFreeBlock == nil) == (mBlockCount == mMaxBlocks));
void* ptr = nil;
if (mNextFreeBlock != nil) {
SBlock* next = mNextFreeBlock->nextFree;
ptr = mNextFreeBlock;
mNextFreeBlock = next;
mBlockCount++;
if (mBlockCount > mMaxBlockCount)
mMaxBlockCount = mBlockCount;
}
return ptr;
}
//---------------------------------------------------------------
//
// TFixedAllocator::Deallocate
//
//---------------------------------------------------------------
void TFixedAllocator::Deallocate(void* ptr)
{
if (ptr != nil) {
SBlock* block = reinterpret_cast<SBlock*>(ptr);
ASSERT(block >= mBlocks);
ASSERT(block < mEndBlock);
block->nextFree = mNextFreeBlock;
mNextFreeBlock = block;
mBlockCount--;
}
}
//---------------------------------------------------------------
//
// TFixedAllocator::ValidateHeap
//
//---------------------------------------------------------------
#if DEBUG
void TFixedAllocator::ValidateHeap(BlockValidateHook hook, void* refCon) const
{
ASSERT(mBlockSize >= sizeof(SBlock));
ASSERT(mBlocks != nil);
ASSERT(mMaxBlocks > 0);
ASSERT(mMaxBlockCount <= mMaxBlocks);
ASSERT(mBlockCount <= mMaxBlockCount);
ASSERT(mEndBlock == reinterpret_cast<SBlock*>((char*) mBlocks + mBlockSize*mMaxBlocks));
ASSERT((mNextFreeBlock == nil) == (mBlockCount == mMaxBlocks));
ASSERT(mNextFreeBlock == nil || (mNextFreeBlock >= mBlocks && mNextFreeBlock < mEndBlock));
if (hook != nil) {
Boolean** inUse = reinterpret_cast<Boolean**>(NewHandle(mMaxBlocks)); // use Boolean since sizeof(bool) may be more than one byte
if (inUse != nil) {
// Mark all the blocks as in use.
SetMemory(*inUse, true, mMaxBlocks);
// Find out which blocks are not in use.
const SBlock* block = mNextFreeBlock;
while (block != nil) {
ulong index = ((char*) block - (char*) mBlocks)/mBlockSize; // can't use straight pointer arithmetic since SBlock is variable length
ASSERT(index < mMaxBlocks);
(*inUse)[index] = false;
block = block->nextFree;
}
// Call the validate hook for each block in use.
for (ulong index = 0; index < mMaxBlocks; index++) {
if ((*inUse)[index]) {
block = reinterpret_cast<const SBlock*>((char*) mBlocks + index*mBlockSize);
ASSERT(block < mEndBlock);
(*hook)(block, (long) mBlockSize, refCon);
}
}
DisposeHandle((Handle) inUse);
} else
DEBUGSTR("Not enough free memory for TFixedAllocator::ValidateHeap");
}
}
#endif
//---------------------------------------------------------------
//
// TFixedAllocator::GetNextBlock
//
//---------------------------------------------------------------
SBlock* TFixedAllocator::GetNextBlock(SBlock* block) const
{
ASSERT(block != nil);
ASSERT(block >= mBlocks);
block = reinterpret_cast<SBlock*>((char*) block + mBlockSize);
if (block >= mEndBlock)
block = nil;
return block;
}